$cardinalDirection[0] = "0 10000 0";    // N
$cardinalDirection[1] = "6000 6000 0";  // NE
$cardinalDirection[2] = "10000 0 0";    // E
$cardinalDirection[3] = "6000 -6000 0"; // SE
$cardinalDirection[4] = "0 -10000 0";   // S
$cardinalDirection[5] = "-6000 -6000 0";// SW
$cardinalDirection[6] = "-6000 0 0";    // W
$cardinalDirection[7] = "-6000 6000 0"; // NW
$NUM_CARDINALS = 8;



datablock PlayerData(FriendlyNPC: PlayerBody)
{
	shapeFile = "~/data/shapes/player/player.dts";
	cmdCategory = "NPC";// Just changing this from 'Client' incase anyone ever needs to use it
	role = "NPC";
	name = "Serra Crewmember";
	range = 6; // detect range
	isInvincible = true; // Set the invincible flag so he doesn't get killed 
};



// We have to override these these methods in order for our bot to properly move.  This is a good thing as it
// allows us to easily set/get a nextTask scoped to our FriendlyNPC object
function FriendlyNPC::onReachDestination(%this,%obj)
{
   // Moves to the next node on the path.
   // Override for all player. Normally we'd override this for only
   // a specific player datablock or class of players.
   if (%obj.path !$= "") {
      if (%obj.currentNode == %obj.targetNode)
         %this.onEndOfPath(%obj,%obj.path);
      else
         %obj.moveToNextNode();
   }
}

function FriendlyNPC::onEndOfPath(%this,%obj,%path)
{
	%obj.nextTask();
	
	// reset - buggy
	//%obj.getDataBlock().schedule(2000, "DoScan", %obj);
}

function FriendlyNPC::onEndSequence(%this,%obj,%slot)
{
	echo("Sequence Done!");
	%obj.stopThread(%slot);
	%obj.nextTask();
}







function FriendlyNPC::Finished(%this, %obj)
{
	%obj.setActionThread("celwave");
}


// Tries to spawn the indexed numbered corpse in the SimGroup, if it exists
function FriendlyNPC::spawn(%this, %index)
{
	%groupName = "MissionGroup/AIDropPoints/" @ %this.role;
    %group = nameToID(%groupName);
	if (%group != -1) 
	{
		%count = %group.getCount();
		if (%count != 0) 
		{
			// We inherit from AIPlayer so we can get access to its functions (like setAimLocation)
			%npc = new AIPlayer() {
				datablock = FriendlyNPC;
				aiPlayer = true;
			};

			// Add it to cleanup when mission ends
			MissionCleanup.add(%npc);

			// Get the location of the spawn sphere and spawn the bot there
			%spawnPoint = %group.getObject(%index);
			%npc.setTransform(%spawnPoint.getTransform());

			%npc.setSkinName("base_blue");
			%npc.setShapeName(%this.name);

			// Have the NPC regularly check to see if there's a player in range
			%npc.getDataBlock().schedule(2000, "DoScan", %npc);
			
			return %npc;
		}
	}
	warn("!! NPC cannot be created: no spawn sphere for this index listed in ", %groupName, "-", %this.role);
}


function FriendlyNPC::RunPath(%this, %obj, %path)
{
	if (!isObject(%path))
		return 0;
		
	// Clear the bot's target
	%obj.clearAim();
	%obj.currentTarget = 0;

	%node = %path.getObject(0);
	
	// Hack: warp the player to the first node in the path in-case he was somehow knocked off
	%obj.setTransform(%node.getTransform());

	// We only have 1 NPC, so this works fine.  Otherwise, we would need some logic to determine which - if any - nodes
	// this NPC should follow, or we would have to adapt a better SimGroup structure to accomodate it
	// Note: this calls AIPlayer::followPath, and tells it to stop when it's reached the 3rd node
	%obj.followPath(%path,2);
	
	%obj.pushTask("geID()");// dummy function; a nextTask() is being called when we initialize the path so we pad an extra event
	%obj.pushTask("getDataBlock().Finished(" @ %obj.getId() @ ")");
}


// Check to see if there's any players nearby
function FriendlyNPC::DoScan(%this, %obj)
{
	// There's a target in range
	if ( (%tgtPlayer = %this.checkForThreat(%obj)) != 0)
	{
		// Face us towards the player
		%obj.setAimObject( %tgtPlayer, "0 0 1" );
		
		// We just acquired a new target
		if (%obj.currentTarget <= 0 || %obj.currentTarget != %tgtPlayer)
		{
			// Do whatever we want to do when we find a new target
			%obj.setActionThread("celsalute");
			//MessageAll("","FRIENDLY NPC SAYS HI");
			centerPrintAll("Serra Guard says, 'Sir!  Thank God you've escaped!'", 4);
			schedule(4000,0,"centerPrintAll","Serra Guard says, 'If you can get me out of this cell, I can lend you a hand.'",8);
			// Save this target so we know if we're already targeting him on next scan
			%obj.currentTarget =  %tgtPlayer;
			
			
			// TODO: WE WANT TO PROBABLY MAKE THIS ITS OWN FUNCTION WHICH IS TRIGGERED WHEN THE JAIL CELL IS OPENED
			// Schedule this bot to run his path
			%path = "MissionGroup/AIDropPoints/NPC/Path1";
			%this.schedule(3000, "RunPath", %obj, %path);
			return 0;
		}
	}
	// No target, go bak to cycling
	else
	{
		// If we had a target, clear it
		if (%obj.getAimObject())
		{
			%obj.clearAim();
			%obj.currentTarget = 0; // forget this target
		}

		// Randomly look around
		// TODO: I could probably just change this to rotate the player in a random direction
		%look = getRandom($NUM_CARDINALS-1);
		if (%this.look != %look)
		{
			%this.look = %look;
		}
		else
		{
			%this.look = %look + 1;
			if (%this.look < $NUM_CARDINALS-1)
				%this.look++;
			else
				%this.look = 0;
		}

		// Look in the direction chosen
		%obj.setAimLocation($cardinalDirection[%this.look]);
	}
	
	// Schedule another scan
	%this.schedule(1500, "DoScan", %obj);
}


// Check if a player is within the npc's range
function FriendlyNPC::checkForThreat(%this, %obj)
{
	// Get the index of the closest player
	%idx = %obj.getDataBlock().getClosestEnemy(%obj);

	// If there was no player found, break out
	if (%idx < 0)
		return 0;

	// Get a reference to the target from the index
	%target = ClientGroup.getObject( %idx );

	// Check if the player is within our range limit
	%tgtPos = %target.player.getPosition();
	%eyePoint = %obj.getWorldBoxCenter();
	%distance = VectorDist(%tgtPos, %eyePoint);

	// If player is within our range, return the player's ID
	if (%distance < %this.range)
	{
		return %target.player;
	}

	// If we got to here, we didn't find anyone in range
	return 0;
}


// Find the closest player to this npc
function FriendlyNPC::getClosestEnemy(%this, %obj) 
{
	%index = -1;
	%botPos = %obj.getPosition();
	%count = ClientGroup.getCount();

	for(%i = 0; %i < %count; %i++)
	{
		%client = ClientGroup.getObject(%i);
		if (%client.player $= "" || %client.player == 0 )
			return -1;
			
		%playPos = %client.player.getPosition();
		%tempDist = VectorDist(%playPos, %botPos);

		// If there's only one player (single player game), it must be the closest player
		if(%i == 0) 
		{
			%distance = %tempDist;
			%index = %i;
		}
		// If there are multiple players, keep track of the closest found
		else 
		{
			if (%distance > %tempDist) 
			{
				%distance = %tempDist;
				%index = %i;
			}
		}
	}
	return %index;
}



// Creates a corpse for each spawn point in the MissionGroup/AIDropPoints/Dead mission group
function CreateNPC()
{
	// Create a corpse for every spawn point in this SimGroup.  Unfortunately we can't just pull this as a variable from DeadPlayer as the object won't exist the first tiem the script is run, thus throwing an error and not compiling
	if ( (%spawnGroup = nameToID("MissionGroup/AIDropPoints/NPC")) >= 0 )
	{
		%count = %spawnGroup.getCount();
		for ( %i = 0; %i < %count; %i++)
		{
			// Spawn the corpse
			FriendlyNPC::spawn(FriendlyNPC, %i);
		}
	}
}
